package com.funcity.resource
{
	import de.polygonal.ds.Itr;
	import de.polygonal.ds.LinkedQueue;
	import de.polygonal.ds.ListSet;
	
	import flash.display.Loader;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.geom.PerspectiveProjection;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;

	public final class ResourceDecoder
	{
		private static const POOL_SIZE:uint = 4;
		private static const PENDING_SIZE:uint = 64;

		private var _decoderPool:Dictionary = new Dictionary();
		private var _decoding:ListSet = new ListSet();
		private var _pending:LinkedQueue = new LinkedQueue(PENDING_SIZE);
		private var _urlToPE:Dictionary = new Dictionary();
		private var _decodeHandler:Function;
		
		public function ResourceDecoder(decodeHandler:Function)
		{
			for (var idx:uint = 0; idx < POOL_SIZE; idx++)
			{
				var decoder:Loader = new Loader();

				decoder.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
				decoder.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
				
				_decoderPool[decoder] = null;
			}
			_decodeHandler = decodeHandler;
		}
				
		public function decode(url:String, data:ByteArray):void
		{
			if (_decoding.has(url))
			{
				return;
			}
			_decoding.set(url);
			
			var decoder:Loader = getDecoder(url);
			if (decoder)
			{
				decoder.loadBytes(data);
			}
			else
			{
				var pendingEntry:Object = new Object();
				pendingEntry.url = url;
				pendingEntry.data = data;
				_urlToPE[url] = pendingEntry;
				_pending.enqueue(pendingEntry);
			}
		}

		private function getDecoder(url:String):Loader
		{
			for (var decoder:Object in _decoderPool)
			{
				if (_decoderPool[decoder] == null)
				{
					_decoderPool[decoder] = url;
					return Loader(decoder);
				}
			}
			return null;
		}
		
		private function finishDecoding(decoder:Loader):String
		{
			var url:String = _decoderPool[decoder];
			_decoding.remove(url);
			return url;
		}
		
		public function cancel(url:String):Boolean
		{
			//没在解码的
			if(_decoding.has(url) == false)
			{
				return true;
			}
			//等待解码的
			var pe:Object = _urlToPE[url];
			if(pe != null)
			{
				_pending.remove(pe);
				delete _urlToPE[url];
				return true;
			}
			//正在解码的
			return false;
		}

		private function decodeNext(decoder:Loader):void
		{
			_decoderPool[decoder] = null;
			decoder.unload();
			
			var iter:Itr = _pending.iterator();
			if (iter.hasNext())
			{
				var pendingEntry:Object = iter.next();
				_pending.dequeue();
				delete _urlToPE[pendingEntry.url];
				_decoderPool[decoder] = pendingEntry.url;
				decoder.loadBytes(pendingEntry.data);
			}
		}
		
		private function errorHandler(e:Event):void
		{
			var decoder:Loader = Loader(e.target.loader);
			var url:String = finishDecoding(decoder);
			
			_decodeHandler(url, null);
			decodeNext(decoder);
		}		
		
		private function completeHandler(e:Event):void 
		{
			var decoder:Loader = Loader(e.target.loader);
			var url:String = finishDecoding(decoder);

			_decodeHandler(url, decoder.contentLoaderInfo);
			decodeNext(decoder);
		}
	}
}